﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using TTUnityPlugin;
using UnityEngine.UI;
using System.Threading;
#if UNITY_EDITOR
using UnityEditor;
#endif
using TTGameEngine;
namespace TTGame
{
    public class Tools
    {
        static Dictionary<int, int> test_PossionCount = new Dictionary<int, int>();

        //减少计算Exp的计算量。
        static Dictionary<float, double> m_ExpCache = new Dictionary<float, double>();

        static double obtainExpCache(float exp)
        {
            if (m_ExpCache.ContainsKey(exp))
            {
                return m_ExpCache[exp];
            }
            else
            {
                double res = System.Math.Exp(exp);
                m_ExpCache.Add(exp, res);
                return res;
            }
        }

        //返回当前时间。单位:100毫微秒。100毫微秒 = 10^-7 秒 = 10^-4毫秒。
        //注：数值太大，不能作为Double返回，会出现精度丢失。在得到时间差值之后再转换单位。
        public static long getTimeInMUS()
        {
            return System.DateTime.Now.Ticks;
        }

        public static float TimeMusToMS(long mus)
        {
            //100毫微秒 = 10^-7 秒 = 10^-4毫秒。
            return mus * 1E-4f;
        }
        public static float TimeMusToSecond(long mus)
        {
            //100毫微秒 = 10^-7 秒 = 10^-4毫秒。
            return mus * 1E-7f;
        }


        public static int PossionRandom(float Lambda)
        {
            int k = 0;
            double p = 1.0;
            double l = obtainExpCache(-Lambda);  /* 为了精度，使用System.math.Exp，exp(-Lambda)是接近0的小数*/

            while (p >= l)
            {
                double u = Random.Range(0.0f, 1.0f);
                p *= u;
                k++;
            }

            int result = k - 1;
            int count = 1;
            if (test_PossionCount.ContainsKey(result))
            {
                count = test_PossionCount[result];
                count++;
                test_PossionCount[result] = count;
            }
            else
            {
                test_PossionCount.Add(result, count);
            }

            DebugUtil.Log("PossionRandom [" + result + "] Count [" + count + "]");
            return result;
        }
        ///*
        // * 产生一个近似符合泊松分布的随机数。（lambda >= 0）
        // * 产生的值是[0，1]
        // *
        // * mark:youhua 速度好卡，使用预先设置好的初始数据，然后随机？
        // */
        //public static float PossionRandonRegion(float Lambda, float min, float max, float area = 1.0f/3.0f)
        //{
        //    /* 产生的泊松分布是（0，正无穷）的随机数。分布中心在lambda。
        //     * 为了保证两边不至于太空旷，现取（1/3l, 5/3l）区间的值。区间之外的值，对折回区间内。
        //     */
        //    float possionValue = PossionRandom(Lambda);
        //    float result = possionValue;
        //    float invL = area * Lambda;
        //    float invR = (2 - area) * Lambda;

        //    if (result < invL)
        //    {
        //        result = (invL - result) + invL;
        //    }
        //    else if (result > 2 * invR)
        //    {
        //        result = invR;
        //    }
        //    else if (result > invR)
        //    {
        //        result = (invR - result) + invR;
        //    }

        //    //现在值，集中在（1/3l, 5/3l）中。再将区间移动至（0，1）
        //    result = (result - invL) / (invR - invL);
        //    //再将区间移动到指定区间（min,max）
        //    result = result * (max - min) + min;

        //    Debug.Log("PossionRandon: " + possionValue + "  result: " + result);

        //    return result;
        //}

        //调用Cmd命令行
        static public void RunCmd(string command)
        {
            DebugUtil.LogFormat("[Tools]Run cmd [{0}]", command);
            Thread newThread = new Thread(new ThreadStart(() =>
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = "cmd.exe";           //确定程序名
                p.StartInfo.Arguments = "/c " + command + " && pause";   //确定程式命令行
                p.StartInfo.UseShellExecute = true;         //是否使用操作系统 shell 启动进程
                p.StartInfo.RedirectStandardInput = false;   //重定向输入
                p.StartInfo.RedirectStandardOutput = false; //重定向输出
                p.StartInfo.RedirectStandardError = false;   //重定向输出错误
                p.StartInfo.CreateNoWindow = false;          //设置置不显示示窗口
                p.Start();
                //return p.StandardOutput.ReadToEnd();        //输出出流取得命令行结果果
            }));
            newThread.Name = "UnityEditorRunCmd";
            newThread.Start();
        }
        static public T GetRandomValueFromList<T>(List<T> list)
        {
            if (list.Count == 0)
            {
                //返回0或null
                return default(T);
            }
            return list[Random.Range(0, list.Count - 1)];
        }

        //协议参数中不能传float，所以转换为int。保留3位精度。
        static public int NetFloatConvertInt(float value)
        {
            return (int)(value * 1000);
        }

        static public float NetIntConvertFloat(int value)
        {
            return value / 1000.0f;
        }

        //     static public void NetReadVector3(SocketClientStream reader, ref Vector3 pos) {
        //         pos.x = reader.ReadFloat();
        //         pos.y = reader.ReadFloat();
        //         pos.z = reader.ReadFloat();
        //     }
        //     static public Vector3 NetReadVector3(SocketClientStream reader) {
        //         float x, y, z;
        //         x = reader.ReadFloat();
        //         y = reader.ReadFloat();
        //         z = reader.ReadFloat();
        //
        //         return new Vector3(x, y, z);
        //     }

        //     static public void NetWriteVector3(SocketClientStream write, Vector3 pos) {
        //         write.WriteFloat(pos.x);
        //         write.WriteFloat(pos.y);
        //         write.WriteFloat(pos.z);
        //     }

        static public void DumpVector3(Vector3 pos, string msg = "")
        {
            DebugUtil.Log(msg + " " + GetDumpVector3Str(pos));
        }

        static public string GetDumpVector3Str(Vector3 pos, string msg = "")
        {
            return "Pos X:" + pos.x + " Y:" + pos.y + " Z:" + pos.z;
        }

        static char[] words = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
                            'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
                            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                            'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
                          };

        /*返回由数字和字符组成的随机字符串。*/
        static public string getRandomStr(int len)
        {
            string str = "";
            for (int i = 0; i < len; i++)
            {
                str += words[Random.Range(0, 62)];
            }
            return str;
        }

        public static Quaternion ForwardToRotate(Vector3 forward)
        {
            Transform tf = GameLauncher.Self.GetCalcObj();
            tf.forward = forward;
            return tf.rotation;
        }

        public static Vector3 RotateToForward(Quaternion rotation)
        {
            Transform tf = GameLauncher.Self.GetCalcObj();
            tf.rotation = rotation;
            return tf.forward;
        }

        public static void EnableAllTextAndImage(GameObject obj, bool b)
        {
            Image[] images = obj.GetComponentsInChildren<Image>();
            foreach (Image image in images)
            {
                image.enabled = b;
            }
            Text[] texts = obj.GetComponentsInChildren<Text>();
            foreach (Text text in texts)
            {
                text.enabled = b;
            }
        }

        public static void SetDirty(Object obj)
        {
#if UNITY_EDITOR
            if (obj)
            {
                UnityEditor.EditorUtility.SetDirty(obj);
            }
#endif
        }


        static public void SetRenderShadowOff(Renderer render)
        {
            //if (ConfigFile.Share().RealLightShadow)
            //{
            //    return;
            //}

            if (!render) return;
            render.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            render.receiveShadows = false;
            render.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
            render.useLightProbes = false;
        }

        static public void SetRenderShadowOff(GameObject root)
        {
            if (root)
            {
                Renderer[] renderList = root.GetComponentsInChildren<Renderer>(true);
                for (int i = 0; i < renderList.Length; i++)
                {
                    SetRenderShadowOff(renderList[i]);
                }
            }
        }

        /// <summary>
        ///通过当前的时间戳返回一个当前datetime
        /// </summary>
        /// <param name="curtimestamp"></param>
        /// <returns></returns>
        public static System.DateTime getCurDatetime(long curtimestamp)
        {
            System.DateTime dateTimeStart = System.TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return dateTimeStart.AddMilliseconds(curtimestamp);
        }

        public static string GetCurTimeString()
        {
            return System.DateTime.Now.ToLongTimeString().ToString();
        }


        /// <summary>
        /// 可以获得隐藏节点。不能获得隐藏的根节点。
        /// 使用说明：获取Scene/lizi/xx_1节点。  => rootName = "Scene"  otherPath="lizi/xx_1"
        /// </summary>
        /// <returns>The node.</returns>
        /// <param name="rootName">Root name.</param>
        /// <param name="otherPath">Other path.</param>
        public static Transform GetNode(string rootName, string otherPath)
        {
            Transform result = null;
            GameObject obj = GameObject.Find(rootName);
            if (obj != null && string.IsNullOrEmpty(otherPath) == false)
            {
                result = obj.transform.Find(otherPath);
            }
            return result;
        }

        public static T GetComponent<T>(string rootName, string otherPath) where T : Component
        {
            T com = default(T);
            GameObject root = GameObject.Find(rootName);
            if (root != null)
            {
                Transform tf = root.transform.Find(otherPath);
                if (tf != null)
                {
                    com = tf.GetComponent<T>();
                }
            }
            return com;
        }


        public static void CombineToOne(GameObject go)
        {
            // 获取物体下所有SkinnedMeshRenderer组件
            SkinnedMeshRenderer[] _smr = go.GetComponentsInChildren<SkinnedMeshRenderer>();
            List<CombineInstance> lcom = new List<CombineInstance>();

            // 材质列表
            List<Material> lmat = new List<Material>();
            // 骨骼列表
            List<Transform> ltra = new List<Transform>();

            // 为三大列表赋值
            for (int i = 0; i < _smr.Length; i++)
            {
                //Unity自动生成的SkinnedMeshRenderer中，材质和骨骼都是编号好的，直接Add
                lmat.AddRange(_smr[i].materials);
                ltra.AddRange(_smr[i].bones);
                // 给网格编号 以便合并
                for (int sub = 0; sub < _smr[i].sharedMesh.subMeshCount; sub++)
                {
                    CombineInstance ci = new CombineInstance();
                    ci.mesh = _smr[i].sharedMesh;
                    ci.subMeshIndex = sub;
                    lcom.Add(ci);
                }
                //GameObject.Destroy(_smr[i].gameObject);
            }

            // 生成新的SkinnedMeshRenderer
            SkinnedMeshRenderer _r = go.GetComponent<SkinnedMeshRenderer>();
            if (_r == null)
            {
                go.AddComponent<SkinnedMeshRenderer>();
                _r = go.GetComponent<SkinnedMeshRenderer>();
            }

            // 赋值
            _r.sharedMesh = new Mesh();
            _r.bones = ltra.ToArray();
            _r.materials = new Material[] { lmat[0] };
            _r.rootBone = go.transform;
            _r.sharedMesh.CombineMeshes(lcom.ToArray(), true, false);

        }




#if UNITY_EDITOR
        //获取场景的根节点，可以获得隐藏的节点。只能用于UnityEditor
        public static List<GameObject> GetSceneRoots()
        {
            List<GameObject> rootObjs = new List<GameObject>();
            var prop = new HierarchyProperty(HierarchyType.GameObjects);
            var expanded = new int[0];
            while (prop.Next(expanded))
            {
                rootObjs.Add(prop.pptrValue as GameObject);
            }
            return rootObjs;
        }
        //获取场景的指定根节点，可以获得隐藏的节点。只能用于UnityEditor
        public static GameObject GetSceneRoot(string name)
        {
            GameObject obj = null;
            var prop = new HierarchyProperty(HierarchyType.GameObjects);
            var expanded = new int[0];
            while (prop.Next(expanded))
            {
                obj = prop.pptrValue as GameObject;
                if (name.Equals(obj.name, System.StringComparison.OrdinalIgnoreCase))
                {
                    return obj;
                }
            }
            return null;
        }

#endif

#if UNITY_EDITOR || DEBUG
        static int curFrameID = 0;

        public static void Debug_UpdateFrameCount()
        {
            curFrameID++;
            if (curFrameID >= int.MaxValue)
            {
                curFrameID = 0;
            }
        }

        public static int Debug_GetCurFrameID()
        {
            return curFrameID;
        }

#endif

        //点是否在对象面前的扇形内，点是否与释放对象夹角小于anglem,以及距离小于扇形边长
        //angle是扇形的全部角度，不是半角。
        static public bool IsPointInCircularSector(Vector3 p, Vector3 center, Vector3 direct, float len, float angle)
        {
            bool isNear = center.distanceLess(p, len);
            if (isNear == false) return false;

            if (angle >= 360f) { return true; }
            Vector3 pointV = p - center;
            if (pointV.IsZero()) { return true; }
            if (angle == 180) { return direct.IsSameDirection(pointV); }

            float realAngle = Vector3.Angle(direct, pointV);
            bool angleInclude = (realAngle <= (angle / 2));
            return angleInclude;
        }

        //点是否在对象面前的扇形内，点是否与释放对象夹角小于anglem,以及距离小于扇形边长
        //
        //！注意：这个版本方法只判断角度！即假设距离已满足。
        //
        //angle是扇形的全部角度，不是半角。
        static public bool IsPointAngleInCircularSector(Vector3 p, Vector3 center, Vector3 direct, float angle)
        {

            if (angle >= 360f) { return true; }
            Vector3 pointV = p - center;
            if (pointV.IsZero()) { return true; }
            if (angle == 180) { return direct.IsSameDirection(pointV); }

            float realAngle = Vector3.Angle(direct, pointV);
            bool angleInclude = (realAngle <= (angle / 2));
            return angleInclude;
        }

        /// <summary>
        /// angle是扇形的全部角度，不是半角。
        /// </summary>
        static public void DrawSector(Vector3 center, Vector3 dir, float len, float angle)
        {
            Gizmos.color = Color.white;
            Gizmos.DrawWireSphere(center, len);

            Gizmos.color = Color.green;
            Vector3 forward = dir * len;
            float halfAngle = angle / 2;
            Vector3 leftSide = Tools.rotateVector3(forward, halfAngle);
            Vector3 rightSide = Tools.rotateVector3(forward, -halfAngle);
            Gizmos.DrawRay(center, leftSide);
            Gizmos.DrawRay(center, rightSide);
        }

        static public void DrawColliderInfo(Transform centerTF, ColliderInfo colInfo)
        {
            switch (colInfo.m_atkShape)
            {
                case ColliderShape.Sphere:
                    Gizmos.DrawWireSphere(centerTF.position, colInfo.m_radius);
                    break;
                case ColliderShape.Rect:
                    Gizmos.DrawWireCube(centerTF.position + colInfo.m_rectCenterOffset, colInfo.m_rectSize);
                    break;
                case ColliderShape.Sector:
                    Tools.DrawSector(centerTF.position, centerTF.forward, colInfo.m_radius, colInfo.m_angle);
                    break;
                case ColliderShape.Line:
                    Gizmos.DrawRay(centerTF.position, centerTF.forward * colInfo.m_moveSpeed * 0.03f * colInfo.m_rayLenFactor);
                    break;
            }
        }

        //向量旋转公式，旋转θ度后得到的新向量坐标。
        //x1＝xcosθ1+ysinθ1,  y1＝-xsinθ1+ycosθ1,  z1＝z
        static public Vector3 rotateVector3(Vector3 direct, float angle)
        {
            float radian = Mathf.Deg2Rad * angle;
            return new Vector3(
                       direct.x * Mathf.Cos(radian) + direct.z * Mathf.Sin(radian),
                       direct.y,
                       -direct.x * Mathf.Sin(radian) + direct.z * Mathf.Cos(radian));
        }

        /// <summary>
        ///点是否在矩形中 xz平面中
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="minx"></param>
        /// <param name="minz"></param>
        /// <param name="maxx"></param>
        /// <param name="maxz"></param>
        /// <returns></returns>
        public static bool IsPointInRect2D(Vector3 pos, float minx, float minz, float maxx, float maxz)
        {
            float posx = pos.x;
            float posz = pos.z;

            if (minx >= maxx)
            {
                DebugUtil.LogError("[LXG]IsPointInRect2D width error!!");
            }
            if (minz >= maxz)
            {
                DebugUtil.LogError("[LXG]IsPointInRect2D height error!!");
            }

            return posx <= maxx && posx >= minx && posz <= maxz && posz >= minz;
        }

        /// <summary>
        /// 点是否在矩形中 xz平面中。
        /// 矩形以方向和长度宽度表示。
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="center">方向向量的起点，矩形的对称轴和某一边相交的点。</param>
        /// <param name="dir">矩形某一对称轴的方向</param>
        /// <param name="width">矩形宽度，注意不是一半的宽度</param>
        /// <param name="len">方向上的长度</param>
        /// <returns></returns>
        public static bool IsPointInRect2D(Vector3 pos, Vector3 startPos, Vector3 dir, float width, float len)
        {
            //将pos转换坐标系，到以startPos为原点，以方向dir为x轴，以矩形的边为y轴的坐标系。
            //A'(x'o'y') = A(xoy) - [oo']
            Vector3 axisDir = Vector3.zero - startPos;
            Vector3 newPos = pos - axisDir;
            return Tools.IsPointInRect2D(newPos, 0, -width / 2, len, width / 2);
        }

        /// <summary>
        /// 点是否在圆形中
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="center"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        public static bool IsPointInCircle(Vector3 pos, Vector3 center, float radius)
        {
            return (pos - center).sqrMagnitude <= radius * radius;
        }


        /// <summary>
        ///检查2D平面上两个矩形是否相交
        /// </summary>
        /// <param name="rect1"></param>
        /// <param name="rect2"></param>
        /// <returns></returns>
        public static bool IsRectIntersect2D(float[] rect1, float[] rect2)
        {
            return !(rect1[0] > rect2[2] || rect2[0] > rect1[2] || rect1[1] > rect2[3] ||
                     rect2[1] > rect1[3]);
        }

        static public bool Vector3Equals(Vector3 pos1, Vector3 pos2)
        {
            if (Mathf.Abs(pos1.x - pos2.x) < 0.0001f
                    && Mathf.Abs(pos1.y - pos2.y) < 0.0001f
                    && Mathf.Abs(pos1.z - pos2.z) < 0.0001f)
            {
                return true;
            }
            return false;
        }
        static public bool IsVectorZero(Vector3 pos1, Vector3 pos2)
        {
            if (Mathf.Abs(pos1.x - pos2.x) < 0.0001f
                    && Mathf.Abs(pos1.y - pos2.y) < 0.0001f
                    && Mathf.Abs(pos1.z - pos2.z) < 0.0001f)
            {
                return true;
            }
            return false;
        }


        //不比较Y轴
        static public bool Vector3Equals2D(Vector3 pos1, Vector3 pos2)
        {
            if (Mathf.Abs(pos1.x - pos2.x) < 0.00001f
                    && Mathf.Abs(pos1.z - pos2.z) < 0.00001f)
            {
                return true;
            }
            return false;
        }

        //考虑各种强制位移的影响
        static public void ObjForceStep(float dt, Vector3 posNow, ICollection<MoveInfo> forceMoveInfos, out Vector3 posNext)
        {
            posNext = posNow;
            if (forceMoveInfos.Count > 0)
            {
                Vector3 sumForce = Vector3.zero;
                foreach (MoveInfo tforceMoveInfo in forceMoveInfos)
                {
                    sumForce += tforceMoveInfo.ForceStep(dt, posNow);
                }
                //             for(int i = 0; i < forceMoveInfos.Count; i++) {
                //                 sumForce += forceMoveInfos[i].ForceStep(dt, posNow);
                //             }
                posNext = posNow + sumForce;
            }
        }

        static public void SetMoveInfoWithTargetObj(MoveInfo moveInfo, MoveStrategy moveStrategy, float aMoveSpeed, Transform targetObjTF, SkillTL skill, string muzzlePosName)
        {
            SkillSelector selector = skill.m_selector;

#if UNITY_EDITOR
            if (moveStrategy == MoveStrategy.Dir_TowardTargetObj
                    || moveStrategy == MoveStrategy.Pos_TargetObjPos
                    || moveStrategy == MoveStrategy.Follow_TargetObj)
            {
                if (targetObjTF == null)
                {
                    DebugUtil.LogWarningFormat("[ForceMoveTrigger] No Obj[{0}] Found forceMoveType:[{1}]", skill.m_selector.ResultLockObjGID, moveStrategy);
                    return;
                }
            }
#endif

            moveInfo.Reset();
            moveInfo.moveSpeed = aMoveSpeed;
            switch (moveStrategy)
            {
                case MoveStrategy.Dir_CasterFace:
                    {
                        moveInfo.SetMoveDir(selector.OwnerObj.objTF.forward);
                    }
                    break;
                case MoveStrategy.Dir_MuzzleForward:
                    {
                        if (string.IsNullOrEmpty(muzzlePosName) == false)
                        {
                            moveInfo.SetMoveDir(selector.OwnerObj.GetPosTF(muzzlePosName).forward);
                        }
                        else
                        {
                            moveInfo.SetMoveDir(Vector3.zero);
                            DebugUtil.LogErrorFormat("[MoveInfo] obj:[{0}] MoveStrategy[{1}] 子弹触发器需要设置muzzlePosName", moveStrategy.ToString(), selector.OwnerObj.GetGID());
                        }
                    }
                    break;
                case MoveStrategy.Dir_SelectorDir:
                    {
                        moveInfo.SetMoveDir(selector.ResultDir);
                    }
                    break;
                case MoveStrategy.Dir_TowardTargetObj:
                    {
                        moveInfo.SetMoveDir(targetObjTF.position - selector.OwnerObj.objTF.position);
                    }
                    break;
                case MoveStrategy.Pos_SelectorPos:
                    {
                        moveInfo.SetMovePos(selector.ResultHitCenter);
                    }
                    break;
                case MoveStrategy.Pos_TargetObjPos:
                    {
                        moveInfo.SetMovePos(targetObjTF.position);
                    }
                    break;
                case MoveStrategy.Follow_TargetObj:
                    {
                        moveInfo.SetMoveFollow(targetObjTF);
                    }
                    break;
            }
        }

        static public bool SetMoveInfoOneTarget(MoveInfo moveInfo, MoveStrategy moveStrategy, float aMoveSpeed, SkillTL skill, string muzzlePosName)
        {
            List<Puppet> objs = skill.GetTargetObjs();

#if UNITY_EDITOR
            if (moveStrategy == MoveStrategy.Dir_TowardTargetObj
                    || moveStrategy == MoveStrategy.Pos_TargetObjPos
                    || moveStrategy == MoveStrategy.Follow_TargetObj)
            {
                if (objs.Count == 0)
                {
                    DebugUtil.LogWarningFormat("[ForceMoveTrigger] No Obj[{0}] Found forceMoveType:[{1}]", skill.m_selector.ResultLockObjGID, moveStrategy);
                    return false;
                }
            }
#endif
            Transform targetObjTF = objs.Count == 0 ? null : objs[0].objTF;
            SetMoveInfoWithTargetObj(moveInfo, moveStrategy, aMoveSpeed, targetObjTF, skill, muzzlePosName);
            return true;
        }

        static public void SetMoveInfoMutiTargets(List<MoveInfo> moveInfos, MoveStrategy moveStrategy, float aMoveSpeed, SkillTL skill, string muzzlePosName)
        {
            List<Puppet> objs = skill.GetTargetObjs();
#if UNITY_EDITOR
            if (moveStrategy == MoveStrategy.Dir_TowardTargetObj
                    || moveStrategy == MoveStrategy.Pos_TargetObjPos
                    || moveStrategy == MoveStrategy.Follow_TargetObj)
            {
                if (objs.Count == 0)
                {
                    DebugUtil.LogWarningFormat("[ForceMoveTrigger] No Obj[{0}] Found forceMoveType:[{1}]", skill.m_selector.ResultLockObjGID, moveStrategy);
                }
            }
#endif
            for (int i = 0; i < objs.Count; i++)
            {
                MoveInfo moveInfo = moveInfos[i];
                SkillSelector selector = skill.m_selector;
                Transform targetObjTF = objs[i].objTF;


                SetMoveInfoWithTargetObj(moveInfo, moveStrategy, aMoveSpeed, targetObjTF, skill, muzzlePosName);
            }
        }

        //随机概率是否命中。  rate:0~1
        static public bool IsHitRate(float rate)
        {
            if (rate >= 1)
                return true;
            if (rate <= 0)
                return false;
            float random = UnityEngine.Random.Range(0f, 1f);
            return random <= rate;
        }
    }
}